import copy
import logging
import typing
from typing import List, Optional, overload

import PySide6.QtCore
import PySide6.QtGui
from PySide6.QtCore import QPoint, QRegularExpression, Qt, Signal
from PySide6.QtGui import QCursor, QIcon, QRegularExpressionValidator
from PySide6.QtWidgets import (QAbstractItemView, QCheckBox, QComboBox,
                               QHeaderView, QLineEdit, QPushButton,
                               QTableWidget, QTableWidgetItem, QTreeWidgetItem)

from ...LittleWidget.LittleWidgetBase import LittleWidgetBase
from ...LittleWidget.LWCheckBox import LWCheckBox
from ...LittleWidget.LWCombox import LWCombox
from ...LittleWidget.LWLabel import LWLabel
from ...LittleWidget.LWLineEdit import LWLineEdit
from ...LittleWidget.LWPushButton import LWPushButton


class TableWidgetGeneral(QTableWidget):
    '''
    discription:
        一个通用的 TableWidget，传入规定格式的 dict(可以json化的)
        就可以实现增删改查
        这是一个显示基础类，要好好写
        这个类还支持 Redo Undo
        加油 赵树成
    functions:
        - __init__(self, head_config: 'dict', parent) -> None:
            根据传入的 head_config 来设置列信息，header_config 的数据结构如下：
                {
                    'headerName1(列头的名称)': {
                        'columnIndex': int(该列在那一列)
                        'width': int(多宽)
                        'resizeMode': str枚举('Fixed', 'Interactive') 默认是 Interactive
                    },
                    'headerName2(列头的名称)': {...},
                }
        - InsertRow(self, row_data: 'dict') -> 'bool':
            插入一列 row_data, row_data 的数据结构如下：
                {
                    'pushButton(列头的名称)': {
                        'type': pushButton,           
                        'property': {
                            'text': str(),
                            'iconPath': str(),
                        }
                    },
                    'lineEdit(列头的名称)': {
                        'type': 'lineEdit',
                        'property': {
                            'text': str(),
                            'regExp': str(),
                        },
                    },
                    'combox(列头的名称)': {
                        'type': 'combox',          # 必选
                        'property': {
                            'currentText': str(),
                            'options': list(),
                        }
                    },
                    'checkBox(列头的名称)': {
                        'type': 'checkBox',         # 必选
                        'property': {
                            'checkState': int        # 可选, 默认为 False
                        },
                    },
                    'label(列头的名称)': {
                        'type': 'label',       # 必选
                        'property': {
                            'text': str(),
                            'iconPath': str(),
                        }
                    }
                }
        - RemoveRow(self, row_index: 'int') -> 'bool':
            移除一行
        - UpdateProperty(self, row: 'int', column: 'int', property: 'dict') -> None
            更新表格中的数据，更新后将触发itemchanged的事件，itemchanged事件会触发内部数据改变的函数
    signals:
        - signalCellWidgetEvent 表格内部的窗体事件
            {
                'event': 字符串枚举(供用户判断是哪种类型的枚举),
                'row': 当前 Cell 的行,
                'colunm': 当前 Column 的列,
            }
    '''
    signalCellWidgetEvent = Signal(dict)
    def __init__(self, header_config: 'dict', parent=None):
        super().__init__(parent=parent)
        # 设置类内数据 ================================
        self._log = logging.getLogger()
        self._hHeader = self.verticalHeader()
        self.verticalHeader().setDragDropMode(QAbstractItemView.InternalMove)
        self.horizontalHeader().setSectionsMovable(True)
        self.setSelectionBehavior(QAbstractItemView.SelectRows)
        self._headerConfig = header_config
        self.verticalHeader().setHidden(True)
        self._columnMapHeaderName = dict()
        self._rowHeight = 25
        # self._tableData = list()
        self._littleWidgetNameMapLittleWidget = {
            'pushButton': LWPushButton,
            'lineEdit': LWLineEdit,
            'combox': LWCombox,
            'checkBox': LWCheckBox,
            'label': LWLabel,
        }
        # =============================================

        # 设置窗体表现 =================================
        self._SetupHeader(self._headerConfig)
        # =============================================

    def _SetupHeader(self, header_config: 'dict') -> 'bool':
        '''
        function:
            设置窗体的Header表现
        '''
        # 遍历一遍dict,找到最大的columnIndex
        max_ = 0
        for column_name_, column_config_ in header_config.items():
            if (not isinstance(column_config_, dict)):
                self.setColumnCount(0)
                self._log.debug('column_config not dict')
                return False
            if (not 'columnIndex' in column_config_.keys()):
                self.setColumnCount(0)
                self._log.debug('columnIndex not in column_config dict')
                return False
            if (column_config_['columnIndex'] > max_):
                max_ = column_config_['columnIndex']
        self.setColumnCount(max_ + 1)
        for column_name_, column_config_ in header_config.items():
            self.setHorizontalHeaderItem(column_config_['columnIndex'], QTableWidgetItem(column_name_))
            self.setColumnWidth(column_config_['columnIndex'], column_config_['width'])
            self._columnMapHeaderName[column_config_['columnIndex']] = column_name_
            if (column_config_.get('resizeMode', None) == 'Fixed'):
                self.horizontalHeader().setSectionResizeMode(column_config_['columnIndex'], QHeaderView.Fixed)
        return True

    def InsertRow(self, data: 'dict', row: 'int' = -1) -> None:
        '''
        function:
            插入一行数据
        '''
        insert_row_ = 0
        if (row >= 0 and row < self.rowCount()):
            insert_row_ = row
            self.insertRow(insert_row_)
        else:
            insert_row_ = self.rowCount()
            self.insertRow(insert_row_)
        self.setRowHeight(insert_row_, self._rowHeight)
        for header_name_, item_config_ in data.items():
            if (header_name_ not in self._headerConfig.keys()):
                continue
            if (not isinstance(item_config_, dict)):
                continue
            type_ = item_config_.get('type', '')
            if (type_ not in self._littleWidgetNameMapLittleWidget.keys()):
                continue
            property_ = item_config_.get('property', dict())
            wig_ = self._littleWidgetNameMapLittleWidget[type_]()
            column_index_ = self._headerConfig[header_name_]['columnIndex']
            self.setItem(insert_row_, column_index_, QTableWidgetItem())
            self.setCellWidget(insert_row_, column_index_, wig_)
            if (isinstance(wig_, LittleWidgetBase)):
                wig_.signalEvent.connect(self._SlotCellWidgetEvent)
                for k_, v_ in property_.items():
                    wig_.UpdateProperty(k_, v_)

    @overload
    def GetProperty(self, row: 'int', column: 'int') -> 'dict':
        ...
    @overload
    def GetProperty(self, row: 'int', header_name: 'str') -> 'dict':
        ...
    def GetProperty(self, *args) -> 'dict':
        arg_0 = args[0]
        arg_1 = args[1]
        column_ = 0
        if (isinstance(arg_1, int)):
            # 重载1 =================
            column_ = arg_1
        elif (isinstance(arg_1, str)):
            # 重载2 =================
            column_ = self._headerConfig.get(arg_1, dict()).get('columnIndex', None)
            if (column_ == None):
                return dict()
        else:
            return dict()
        wig_ = self.cellWidget(arg_0, column_)
        if (not isinstance(wig_, LittleWidgetBase)):
            return dict()
        return  wig_.GetProperty()


    def GetRowProperty(self, row: 'int') -> typing.List['dict']:
        '''
        function:
            获取一行的数据属性
        '''
        if (not (row >= 0 and row < self.rowCount())):
            return list()
        l_return_ = list()
        for c_ in range(self.columnCount()):
            l_return_.append(self.GetProperty(row, c_))
        return l_return_
    
    def GetTableProperty(self) -> typing.List[typing.List['dict']]:
        '''
        function:
            获取整个表的数据属性
        '''
        l_return_ = list()
        for r_ in range(self.rowCount()):
            l_return_.append(self.GetRowProperty(r_))
        return l_return_

    def _GetLittleWidgetType(self, wig: 'LittleWidgetBase') -> 'str':
        '''
        function:
            获取一个 LittleWidgetBase 对象的类型
        '''
        if (isinstance(wig, LWCheckBox)):
            return 'checkBox'
        if (isinstance(wig, LWCombox)):
            return 'combox'
        if (isinstance(wig, LWLabel)):
            return 'label'
        if (isinstance(wig, LWLineEdit)):
            return 'lineEdit'
        if (isinstance(wig, LWCheckBox)):
            return 'checkBox'
        return ''

    def _SlotCellWidgetEvent(self, event: 'str', wig: 'LittleWidgetBase') -> None:
        '''
        function:
            cellWidgetEvent事件
            - 收到 CellEvent 事件后，封上cellWidget属性发出去
        '''
        pos_ = wig.pos()
        item_ = self.itemAt(pos_)
        d_ = {
            'event': event,
            'row': item_.row(),
            'column': item_.column(),
        }
        self.signalCellWidgetEvent.emit(d_)

    def UpdateProperty(self, row: 'int', column: 'int', property: 'dict') -> None:
        '''
        function:
            更新某个cellWdiegt的属性
        '''
        wig_ = self.cellWidget(row, column)
        if (not isinstance(wig_, LittleWidgetBase)):
            return
        for k_, v_ in property.items():
            wig_.UpdateProperty(k_, v_)
